home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / nn.zip / SAVE.C < prev    next >
C/C++ Source or Header  |  1989-12-31  |  16KB  |  699 lines

  1. #include <signal.h>
  2. #include <errno.h>
  3. #include "config.h"
  4. #include "term.h"
  5. #include "keymap.h"
  6. #include "news.h"
  7.  
  8. /*
  9.  * save (or print) articles
  10.  */
  11.  
  12. /* #define PAGED_OUTPUT        /* does not work yet!! */
  13.  
  14. export char *default_save_file = "+$F";
  15. export char *unshar_header_file = "Unshar.Headers";
  16. export int  use_mail_folders = 0;
  17. export int  use_mmdf_folders = 0;
  18. export int  save_report = 1;
  19. export int  quick_save = 0;
  20. export int  conf_append = 0;
  21. export int  conf_create = 1;
  22.  
  23. export char *save_counter_format = "%d";    /* format of save counter */
  24.  
  25. export char printer[FILENAME] = PRINTER;    /* lp -s -ol        */
  26. export char *patch_command = "patch";
  27. export char *unshar_command = SHELL;
  28.  
  29. extern int file_completion();
  30.  
  31. import char *temp_file;
  32. import int  shell_restrictions;
  33.  
  34. static int save_mode;
  35. static char *unshar_cmd;
  36.  
  37. #define    HEADER_HANDLING    0x0f    /* what should we do with the header */
  38.  
  39. #define NO_HEADER    0    /* save without a header */
  40. #define    FULL_HEADER    1    /* save with full header */
  41. #define SHORT_HEADER    2    /* save with partial header */
  42. #define    SHORT_HEADER_DG    3    /* save with partial header (digest) */
  43.  
  44.  
  45. #define    SEPARATE_FILES    0x0100    /* save as separate files */
  46. #define UNIQUE_FILES    0x0200    /* save in unique files */
  47. #define    FILE_IS_NEW    0x0400    /* this is a new file */
  48. #define APPEND_ARTNUM    0x0800    /* append article number to file name */
  49. #define    IS_PIPE        0x1000    /* output is on pipe */
  50. #define    DO_UNSHAR    0x2000    /* unshar article (or patch) */
  51. #define    DO_PATCH    0x4000    /* patch article */
  52. #define    DO_DECODE    0x8000    /* uudecode article */
  53.  
  54. /* open modes for open_news_article for the various HEADER_HANDLINGs */
  55.  
  56. static int open_mode[] = {
  57.     SKIP_HEADER,
  58.     0,
  59.     FILL_NEWS_HEADER | SKIP_HEADER,
  60.     FILL_DIGEST_HEADER | SKIP_HEADER
  61. };
  62.  
  63. static FILE *save_file;            /* output stream for saved files */
  64. static char *save_name;            /* save file name */
  65.  
  66. #ifdef PAGED_OUTPUT
  67. static FILE *pager_stream = NULL;    /* unshar/patch output stream */
  68. static char pager_redir[40];
  69. #endif
  70.  
  71. static int counter_index;        /* index into save_name of '*' */
  72. static int uniq_counter;        /* separate files counter */
  73.  
  74. static char last_dir[FILENAME] = "";
  75.  
  76. char *init_save(command, mode_textp)
  77. char command;
  78. char **mode_textp;
  79. {
  80.     char *mode_text;
  81.     static char last_input[FILENAME] = "";
  82.     static char name_buf[512];    /* buffer for file name & command expansion */
  83.     char *start, *last, *np;
  84.     char *ckdir_path();
  85.  
  86.     uniq_counter = 0;
  87.  
  88.     switch (command) {
  89.  
  90.      case K_SAVE_FULL_HEADER:
  91.     save_mode = FULL_HEADER;
  92.     mode_text = "Save";
  93.     goto cont_save;
  94.  
  95.      case K_SAVE_SHORT_HEADER:
  96.     save_mode = SHORT_HEADER;
  97.     mode_text = "Output";
  98.     goto cont_save;
  99.     
  100.      case K_SAVE_NO_HEADER:
  101.     save_mode = NO_HEADER;
  102.     mode_text = "Write";
  103.  
  104.      cont_save:
  105.     if (quick_save && (current_group->group_flag & G_FOLDER) == 0) {
  106.         if (current_group->save_file)
  107.         save_name = current_group->save_file;
  108.         else
  109.         save_name = default_save_file;
  110.         strcpy(last_input, save_name);
  111.         save_name = last_input;
  112.     } else {
  113.         prompt("\1%s on\1 (+~|) ", mode_text);
  114.  
  115.         save_name = get_s(last_input, current_group->save_file, NONE, 
  116.               file_completion);
  117.         if (save_name == NULL || *save_name == NUL) return NULL;
  118.  
  119.         if (save_name[1] == NUL && save_name[0] == '+')
  120.         save_name = default_save_file;
  121.         else
  122.         if (current_group->save_file == NULL ||
  123.             strcmp(save_name, current_group->save_file))
  124.             strcpy(last_input, save_name);
  125.     }
  126.     
  127.     if (*save_name == '|') {
  128.         if (shell_restrictions) {
  129.         msg("Restricted operation - pipes not allowed");
  130.         return NULL;
  131.         }
  132.         mode_text = "Pipe";
  133.         save_name++;
  134.         save_mode |= IS_PIPE;
  135.         if (*save_name == '|' || *save_name == '*') {
  136.         save_mode |= SEPARATE_FILES;
  137.         save_name++;
  138.         }
  139.     } else {
  140.         counter_index = strlen(save_name) - 1;
  141.         np = save_name + counter_index;
  142.         if (*np == '*')
  143.         save_mode |= SEPARATE_FILES | UNIQUE_FILES;
  144.         else
  145.         if (counter_index > 0 && strcmp(--np, "$N") == 0) {
  146.             if (current_group->group_flag & G_FOLDER) {
  147.             msg("$N is not defined in a folder");
  148.             return NULL;
  149.             }
  150.             counter_index--;
  151.             strcpy(np, "*");
  152.             save_mode |= SEPARATE_FILES | APPEND_ARTNUM;
  153.         }
  154.     }
  155.     break;
  156.  
  157.      case K_UUDECODE:
  158.     save_mode = NO_HEADER | DO_UNSHAR | DO_DECODE;
  159.     mode_text = "Decode";
  160.     goto patch1;
  161.     
  162.      case K_PATCH:
  163.     save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR | DO_PATCH;
  164.     mode_text = "Patch";
  165.     unshar_cmd = patch_command;
  166.     goto patch1;
  167.     
  168.      case K_UNSHAR:
  169.     save_mode = NO_HEADER | SEPARATE_FILES | DO_UNSHAR;
  170.     mode_text = "Unshar";
  171.     unshar_cmd = unshar_command;
  172.     
  173.      patch1:
  174.     prompt("\1%s Directory:\1 ", mode_text);
  175.     save_name = get_s(last_dir, current_group->save_file, NONE, file_completion);
  176.     if (save_name == NULL || *save_name == NUL) return NULL;
  177.     strcpy(last_dir, save_name);
  178.     break;
  179.     
  180.      case K_PRINT:
  181.  
  182.     save_mode = SHORT_HEADER | IS_PIPE;
  183.  
  184.     if (shell_restrictions) {
  185.         save_name = printer;
  186.     } else {
  187.         prompt("\1Print command:\1 ");
  188.         save_name = get_s(NONE, printer, NONE, NO_COMPLETION);
  189.         if (save_name == NULL || *save_name == NUL) return NULL;
  190.         strcpy(printer, save_name);
  191.     }
  192.     mode_text = "Print";
  193.     break;
  194.  
  195.      default:
  196.     msg("Illegal save command: %d", command);
  197.     return NULL;
  198.     }
  199.  
  200.     if (save_name) {
  201.     
  202.     if (save_mode & IS_PIPE || *save_name == '+' || *save_name == '~') {
  203.         if (!expand_file_name(name_buf, save_name))
  204.         return NULL;
  205.         if (save_mode & SEPARATE_FILES)
  206.         counter_index = strlen(name_buf) - 1;
  207.     } else
  208.         strcpy(name_buf, save_name);
  209.     
  210.     save_name = name_buf;
  211.     
  212.     if (!(save_mode & IS_PIPE)) {
  213.         if (file_exist(save_name, (save_mode & DO_UNSHAR) ? "wd" : "wf")) {
  214.         if (save_mode & DO_UNSHAR) {
  215.             int len = strlen(save_name);
  216.             if (save_name[len - 1] != '/')
  217.             strcpy(save_name + len, "/");
  218.         } else
  219.         if (conf_append) {
  220.             printf("\rAppend to: %s ? ", save_name);
  221.             clrline();
  222.             if (!yes(0)) return NULL;
  223.         }
  224.         } else {
  225.         if (errno != ENOENT) {
  226.             msg("Cannot access %s", save_name);
  227.             return NULL;
  228.         }
  229.  
  230.         if (save_mode & DO_UNSHAR) {
  231.             int len = strlen(save_name);
  232.             if (save_name[len - 1] != '/')
  233.             strcpy(save_name + len, "/");
  234.         }
  235.  
  236.         start = ckdir_path(save_name);
  237.         if (start == NULL) {
  238.             msg("No permission");
  239.             return NULL;
  240.         }
  241.         
  242.         last = strrchr(start, '/');
  243.         /* last != NULL => non-existing directories */
  244.         
  245.         if (conf_create && (!(save_mode & SEPARATE_FILES) || last)) {
  246.             printf("\rCreate ");
  247.             for (np = save_name; *np; np++) {
  248.             if (np == start) putchar('\"');
  249.             putchar(*np);
  250.             if ((save_mode & SEPARATE_FILES) && np == last) break;
  251.             }
  252.             printf("\" ?");
  253.             clrline();
  254.             if (yes(last != NULL) <= 0) return NULL;
  255.         }
  256.         
  257.         if (last && !mkdirs_in_path(save_name, start)) 
  258.             return NULL;
  259.         }
  260.     }    
  261.     }
  262.     
  263.     if (mode_textp) *mode_textp = mode_text;
  264.  
  265.     save_mode |= FILE_IS_NEW;    /* so save() will open it */
  266.  
  267.     if (save_mode & DO_DECODE) {
  268.     uud_start(save_name);
  269.     save_mode &= ~DO_UNSHAR;
  270.     }
  271.     
  272. #ifdef PAGED_OUTPUT
  273.     if (save_mode & DO_UNSHAR) {
  274.     int was_raw = unset_raw();
  275.     pager_stream = popen(pager, "w");
  276.     if (was_raw) raw();
  277.     
  278.     if (pager_stream == NULL) {
  279.         pager_redir[0] = NUL;
  280.         msg("Warning: Pager '%s' not found");
  281.     } else
  282.         sprintf(pager_redir, " 1>&%d 2>&1 ; ", fileno(pager_stream));
  283.     system("fdcheck");
  284.     }
  285. #endif
  286.  
  287.     return save_name;
  288. }
  289.  
  290.  
  291. save(ah)
  292. article_header *ah;
  293. {
  294.     register FILE *art;
  295.     register c, lcount, mode;
  296.     news_header_buffer hdrbuf;
  297.     int was_raw = 0;
  298.     char copybuf[1024];
  299.  
  300.     if (ah->a_group) init_group(ah->a_group);
  301.     
  302.     mode = save_mode & HEADER_HANDLING;
  303.     if (mode == SHORT_HEADER && ah->flag & A_DIGEST) 
  304.     mode = SHORT_HEADER_DG;
  305.     
  306.     art = open_news_article(ah, open_mode[mode], hdrbuf, (char *)NULL);
  307.     if (art == NULL) {
  308.     msg("Cannot read %s", group_path_name);
  309.     return 0;
  310.     }
  311.  
  312.     if (save_mode & DO_DECODE) {
  313.     save_file = NULL;
  314.     c = uudecode(ah, art);
  315.     fclose(art);
  316.     return (c < 0) ? 0 : 1;
  317.     }
  318.     
  319.     if (save_mode & UNIQUE_FILES) {
  320.     do {
  321.         uniq_counter++;
  322.         sprintf(copybuf, save_counter_format, uniq_counter);
  323.         if (strcmp(save_name + counter_index, copybuf) == 0) {
  324.         msg("save-counter \"%s\" does not generate unique file names",
  325.             save_counter_format);
  326.         goto fatal;
  327.         }
  328.         strcpy(save_name + counter_index, copybuf);
  329.     } while (file_exist(save_name, (char *)NULL));
  330.  
  331.     save_mode |= FILE_IS_NEW;
  332.     } else
  333.     if (save_mode & APPEND_ARTNUM)
  334.         sprintf(save_name + counter_index, "%d", ah->a_number);
  335.         
  336.     if (save_mode & FILE_IS_NEW) {
  337.     if (save_mode & (IS_PIPE | DO_UNSHAR))
  338.         was_raw = unset_raw();
  339.  
  340.     if (save_mode & IS_PIPE) {
  341.         if ((save_file = popen(save_name, "w")) == NULL) {
  342.         msg("Cannot pipe to %s", save_name);
  343.         goto fatal;
  344.         }
  345.     } else
  346.     if (save_mode & DO_UNSHAR) {
  347.         if ((save_mode & DO_PATCH) == 0) {
  348.         if (!unshar_position(art)) 
  349.             goto fatal;
  350.         if (unshar_header_file)
  351.             store_header(ah, art, save_name, unshar_header_file);
  352.         }
  353.  
  354.         if (save_name) 
  355. #ifdef PAGED_OUTPUT
  356.         sprintf(copybuf, "cd %s && %s %s", save_name, unshar_cmd, pager_redir);
  357.         else
  358.         sprintf(copybuf, "%s %s", unshar_cmd, pager_redir);
  359. #else
  360.         new_temp_file();
  361.         sprintf(copybuf, 
  362.             "cd %s && { %s 2>&1 ; } | tee %s ; cat %s >> %s.Result ; rm %s",
  363.             save_name != NULL ? save_name : ".", unshar_cmd,
  364.             temp_file, temp_file, 
  365.             (save_mode & DO_PATCH) ? "Patch" : "Unshar",
  366.             temp_file);
  367. #endif
  368.         save_file = popen(copybuf, "w");
  369.         if (save_file == NULL) {
  370.         msg("Cannot exec: '%s'", copybuf);
  371.         goto fatal;
  372.         }
  373. #ifdef PAGED_OUTPUT
  374.         fprintf(pager_stream, "\r\n%s %s\r\n", 
  375.             save_mode & DO_PATCH ? "PATCHING FROM" : "UNPACKING",
  376.             ah->subject ? ah->subject : "ARTICLE");
  377.         fflush(pager_stream);
  378. #else
  379.         printf("\r\n%s %s\r\n", 
  380.            save_mode & DO_PATCH ? "PATCHING FROM" : "UNPACKING",
  381.            ah->subject ? ah->subject : "ARTICLE"); fl;
  382. #endif
  383.     } else {
  384.         if ((save_file = open_file(save_name, OPEN_APPEND)) == NULL) {
  385.         msg("Cannot write %s", save_name);
  386.         fclose(art);
  387.         return 0;
  388.         }
  389.         if (ftell(save_file) != (off_t)0)
  390.         save_mode &= ~FILE_IS_NEW;
  391.     }
  392.     }
  393.     
  394.     clrline();
  395.     s_pipe = 0;
  396.  
  397.     if (mode != NO_HEADER)
  398.     mailbox_format(save_file, 1);
  399.  
  400.     if (mode == FULL_HEADER) {
  401.     off_t cnt = ah->fpos - ah->hpos;
  402.     while (--cnt >= 0) {
  403.         if ((c = getc(art)) == EOF) break;
  404.         putc(c, save_file);
  405.     }
  406.     } else
  407.     if (mode == SHORT_HEADER) {
  408.     if (news.ng_from)
  409.         fprintf(save_file, "From: %s\n", news.ng_from);
  410.     if (news.ng_date)
  411.         fprintf(save_file, "Date: %s\n", news.ng_date);
  412.     if (news.ng_subj)
  413.         fprintf(save_file, "Subject: %s\n", news.ng_subj);
  414.     fputc(NL, save_file);
  415.     } else
  416.     if (mode == SHORT_HEADER_DG) {
  417.     if (digest.dg_from)
  418.         fprintf(save_file, "From: %s\n", digest.dg_from);
  419.     if (digest.dg_date)
  420.         fprintf(save_file, "Date: %s\n", digest.dg_date);
  421.     if (digest.dg_subj)
  422.         fprintf(save_file, "Subject: %s\n", digest.dg_subj);
  423.     fputc(NL, save_file);
  424.     }
  425.  
  426.     fflush(save_file);
  427.     if (s_pipe) goto broken_pipe;
  428.  
  429.     mode = mode != NO_HEADER && (save_mode & (IS_PIPE | DO_UNSHAR)) == 0;
  430.     
  431.     lcount = 0; 
  432.     while (ftell(art) < ah->lpos && fgets(copybuf, 512, art)) {
  433.     lcount++;
  434.     if (mode && is_header_line(copybuf))
  435.         fputc('~', save_file);
  436.     fputs(copybuf, save_file);
  437.     if (s_pipe) goto broken_pipe;
  438.     }
  439.     
  440.     if (mode != NO_HEADER) 
  441.     lcount += mailbox_format(save_file, 0);
  442.     
  443. broken_pipe:    
  444.     fclose(art);
  445.  
  446.     if (save_mode & DO_UNSHAR) {
  447.     pclose(save_file);
  448.     save_file = NULL;
  449.     } else {
  450.     if (s_pipe)
  451.         msg("Command did not read complete article!");
  452.     else
  453.         if (save_report)
  454.         msg((save_mode & IS_PIPE)     ? "%s: %d lines piped" :
  455.         (save_mode & FILE_IS_NEW) ? "%s created: %d lines written" :
  456.         "%s: %d lines appended", save_name, lcount);
  457.     
  458.     if (s_pipe || (save_mode & SEPARATE_FILES))
  459.         end_save();
  460.     else
  461.         save_mode &= ~FILE_IS_NEW;
  462.     }
  463.     
  464. #ifdef MAIL_READING
  465.     if (mail_auto_delete && (save_mode & IS_PIPE) == 0)
  466.     if (current_group->group_flag & G_MAILBOX)
  467.         if ((ah->flag & A_CANCEL) == 0) 
  468.         fcancel(ah);
  469. #endif    
  470.     if (was_raw) raw();    
  471.  
  472.     ah->flag |= A_ST_FILED;
  473.     
  474.     return !s_pipe || (save_mode & SEPARATE_FILES);
  475.  
  476.  fatal:
  477.     if (was_raw) raw();
  478.     fclose(art);
  479.     return 0;
  480. }
  481.  
  482.  
  483. end_save()
  484. {
  485.     if (save_file) {
  486.     if (save_mode & (IS_PIPE | DO_UNSHAR))
  487.         pclose(save_file);
  488.     else
  489.         fclose(save_file);
  490.     save_file = NULL;
  491.     }
  492.     
  493.     if (save_mode & DO_DECODE) {
  494.     uud_end();
  495.     }
  496. #ifdef PAGED_OUTPUT
  497.     if (pager_stream != NULL) {
  498.     pclose(pager_stream);
  499.     pager_stream = NULL;
  500.     }
  501. #else
  502.     if (save_mode & DO_UNSHAR) {
  503.     import char *delayed_msg;
  504.     
  505.     delayed_msg = (save_mode & DO_PATCH) ?
  506.         "Output is saved in Patch.Result" :
  507.         "Output is saved in Unshar.Result";
  508.     }
  509. #endif
  510. }
  511.  
  512. store_header(ah, f, dir, file)
  513. article_header *ah;
  514. FILE *f;
  515. char *dir, *file;
  516. {
  517.     register int c;
  518.     off_t endpos;
  519.     FILE *h;
  520.     
  521.     if (dir != (char *)NULL && file[0] != '/')
  522.     file = relative(dir, file);
  523.     if ((h = open_file(file, OPEN_APPEND)) == NULL) {
  524.     msg("Cannot open %s", file);
  525.     return;
  526.     }
  527.     fseek(h, (off_t)0, 2);
  528.     if (!use_mmdf_folders && ftell(h) > 0) putc(NL, h);  /* just in case */
  529.     mailbox_format(h, 1);
  530.     endpos = ftell(f) - ah->hpos;
  531.     fseek(f, ah->hpos, 0);
  532.     while (--endpos >= 0 && (c = getc(f)) != EOF) 
  533.     putc(c, h);
  534.     
  535.     mailbox_format(h, 0);
  536.     fclose(h);
  537. }
  538.  
  539. mailbox_format(f, top)
  540. FILE *f;
  541. int top;
  542. {
  543.     time_t now;
  544.     char *ctime();
  545.  
  546.     if (use_mmdf_folders) {
  547.     fprintf(f, "\001\001\001\001\n");
  548.     return 0;
  549.     }
  550.     
  551.     if (top == 0) {
  552.     fputc(NL, f);
  553.     return 1;
  554.     }
  555.     
  556.     if (use_mail_folders) {
  557.     time(&now);
  558.     fprintf(f, "From %s %s", 
  559.         current_group->group_name, ctime(&now));
  560.     return 1;
  561.     }
  562.  
  563.     return 0;
  564. }
  565.  
  566. char *run_mkdir(dir, name_buf)
  567. char *dir, *name_buf;
  568. {
  569.     if (dir == NULL) {
  570.     prompt("\1Directory: \1");
  571.     dir = get_s(last_dir, NONE, NONE, file_completion);
  572.     if (dir == NULL || *dir == NUL) return NULL;
  573.     strcpy(last_dir, dir);
  574.     }
  575.     
  576.     if (*dir == '+' || *dir == '~') {
  577.     if (!expand_file_name(name_buf, dir))
  578.         return NULL;
  579.     dir = name_buf;
  580.     }
  581.     
  582.     if (file_exist(dir, (char *)NULL)) {
  583.     msg("Directory %s already exists", dir);
  584.     return NULL;
  585.     }
  586.     
  587.     if (mkdir(dir, 0755)) {
  588.     msg("Cannot make %s", dir);
  589.     return NULL;
  590.     }
  591.     
  592.     return dir;
  593. }
  594.  
  595.  
  596. change_dir(dir, in_init)
  597. char *dir;
  598. int in_init;
  599. {
  600.     char dir_buf[FILENAME];
  601.         
  602.     if (dir == NULL) {
  603.     prompt("\1Directory: \1");
  604.     dir = get_s(last_dir, NONE, NONE, file_completion);
  605.     }
  606.  
  607.     if (dir == NULL || *dir == NUL) return 0;
  608.     
  609.     strcpy(last_dir, dir);
  610.         
  611.     if (*dir == '+' || *dir == '~') {
  612.     if (!expand_file_name(dir_buf, dir)) return in_init;
  613.     dir = dir_buf;
  614.     }
  615.  
  616.     if (chdir(dir) == 0) {
  617.     if (!in_init) msg("Directory: %s", dir);
  618.     return 0;
  619.     }
  620.     
  621.     if (in_init) return 1;
  622.     
  623.     if (errno == EACCES)
  624.     msg("Cannot access directory %s", dir);
  625.     else {
  626.     /* should ask and create directory here */
  627.     msg("Directory not found: %s", dir);
  628.     }
  629.     
  630.     return 0;
  631. }
  632.  
  633.  
  634.  
  635. /*
  636.  * return pointer to first path name component, that does not exist
  637.  */
  638.  
  639. static char *ckdir_path(name)
  640. char *name;
  641. {
  642.     char *slash;
  643.     char *component;
  644.     
  645.     component = name;
  646.     
  647.     while (slash = strchr(component, '/')) {
  648.     if (slash == component) {
  649.         /*  ...//...  */
  650.         component++;
  651.         continue;
  652.     }
  653.     *slash = NUL;
  654.     if (file_exist(name, "drx")) {
  655.         *slash++ = '/';
  656.         component = slash;
  657.         continue;
  658.     }
  659.     if (file_exist(name, (char *)NULL)) {
  660.         *slash = '/';
  661.         return NULL;
  662.     }
  663.     *slash = '/';
  664.     break;
  665.     }
  666.     return component;
  667. }
  668.  
  669. /*
  670.  * create directories in path name, starting from start
  671.  */
  672.  
  673. static mkdirs_in_path(name, start)
  674. char *name, *start;
  675. {
  676.     char *slash;
  677.     char *component;
  678.     
  679.     component = start;
  680.     
  681.     while (slash = strchr(component, '/')) {
  682.     if (slash == component) {
  683.         /*  ...//...  */
  684.         component++;
  685.         continue;
  686.     }
  687.     *slash = NUL;
  688.     if (mkdir(name, 0755)) {
  689.         msg("Cannot make %s/", name);
  690.         *slash = '/';
  691.         return 0;
  692.     }
  693.     *slash++ = '/';
  694.     component = slash;
  695.     }
  696.     return 1;
  697. }
  698.  
  699.